<?php
/**
 *------------------------------------------------------------------------------
 * @package       Plazart Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/plazartfw
 * @Link:         http://plazart-framework.org
 *------------------------------------------------------------------------------
 */

// No direct access
defined('_JEXEC') or die();

Plazart::import ('extendable/extendable');

/**
 * PlazartTemplate class provides extended template tools used for Plazart framework
 *
 * @package Plazart
 */
class PlazartTemplate extends ObjectExtendable
{
    /**
     * Define constants
     *
     */
    protected static $maxcol = array( 'default' => 6, 'wide' => 6, 'normal' => 6, 'xtablet' => 4, 'tablet' => 3, 'mobile' => 2 );
    protected static $minspan = array( 'default' => 2, 'wide' => 2, 'normal' => 2, 'xtablet' => 3, 'tablet' => 4, 'mobile' => 6 );
    protected static $maxgrid = 12;
    protected static $maxcolumns = 6;

    /**
     *
     * Known Valid CSS Extension Types
     * @var array
     */
    protected static $cssexts = array(".css", ".css1", ".css2", ".css3");

    /**
     * Current template instance
     */
    public $_tpl = null;

    /**
     * Store layout settings if exist
     */
    protected $_layoutsettings = null;

    /**
     * Class constructor
     *
     * @param   object  $template Current template instance
     */
    public function __construct($template = null)
    {
        $this->_layoutsettings = new JRegistry;

        if ($template) {
            $this->_tpl = $template;
            $this->_extend(array($template));
            // merge layout setting

            $layout = JFactory::getApplication()->input->getCmd('plazartlayout', '');
            if(empty($layout)){
                $layout = $template->params->get('mainlayout', 'default-joomla-3.x');
            }
            $fconfig = JPATH_ROOT . '/templates/' . $template->template . '/etc/layout/' . $layout . '.ini';
            if(is_file($fconfig)){
                $this->_layoutsettings->loadString (JFile::read($fconfig), 'INI', array('processSections' => true));
            }
        }
    }

    /**
     * get template parameter
     *
     * @param   $name  parameter name
     * @param   $default  parameter default value
     *
     * @return   parameter value
     */
    public function getParam ($name, $default = null) {
        return $this->_tpl->params->get ($name, $default);
    }

    public function setParam ($name, $value) {
        return $this->_tpl->params->set ($name, $value);
    }

    /**
     * Get current layout tpls
     *
     * @return string Layout name
     */
    public function getLayout () {
        return JFactory::getApplication()->input->getCmd ('tmpl') ? JFactory::getApplication()->input->getCmd ('tmpl') : $this->getParam('layout');
    }

    /**
     * Get layout settings
     *
     * @return string Layout name
     */
    public function getLayoutSetting ($name, $default = null) {
        return isset($this->_layoutsettings) ? $this->_layoutsettings->get($name, $default) : $default;
    }
    /**
     * Load block content
     *
     * @param $block string
     *     Block name - the real block is tpls/blocks/[blockname].php
     *
     * @return string Block content
     */
    function loadBlock($block, $vars = array())
    {
        $path = PlazartPath::getPath ('layouts/blocks/'.$block.'.php');
        if ($path) {
            include $path;
        } else {
            echo "<div class=\"error\">Block [$block] not found!</div>";
        }
    }

    /**
     * Load block content
     *
     * @param $block string
     *     Block name - the real block is tpls/blocks/[blockname].php
     *
     * @return string Block content
     */
    function loadLayout($layout)
    {
        $path = PlazartPath::getPath ('layouts/'.$layout.'.php', 'layouts/default.php');

        if (is_file ($path)) {
            include $path;
        } else {
            echo "<div class=\"error\">Layout [$layout] or [Default] not found!</div>";
        }
    }

    /**
     * Load spotlight block
     *
     * @param $name string
     *     Name of the spotlight. Default will load positions base on this name: [name]-1, [name]-2...
     * @param $default_cols integer
     *     Default columns in the spotlight, changable in admin
     *
     */
    function spotlight($name, $positions, array $info = array())
    {
        $defpos = preg_split('/\s*,\s*/', $positions);
        $vars = is_array($info) ? $info : array();
        $cols = count($defpos);
        $poss = $defpos;

        $splparams = array();
        for($i = 1; $i <= self::$maxcolumns; $i++){
            $param = $this->getLayoutSetting('block'.$i.'@'.$name);
            if(empty($param)){
                break;
            } else {
                $splparams[] = $param;
            }
        }

        //we have configuration in setting file
        if(!empty($splparams)){
            $poss = array();
            foreach ($splparams as $idx => $splparam) {
                $param = (object)$splparam;
                $poss[] = isset($param->position) ? $param->position : $defpos[$idx];
            }

            $cols = count($poss);
        }

        // check if there's any modules
        if (!$this->countModules (implode(' or ', $poss))){
            return;
        }

        //empty - so we will use default configuration
        if(empty($splparams)){
            //generate a optimize default width
            $default = $this->genWidth('default', $cols);
            foreach ($poss as $i => $pos) {
                //is there any configuration param
                $var = isset($vars[$pos]) ? $vars[$pos] : '';

                $param = new stdClass;
                $param->position = $pos;

                $param->default = ($var && isset($var['default'])) ? $var['default'] : 'span' . $default[$i];
                if($var){
                    if(isset($var['wide'])){
                        $param->wide = $var['wide'];
                    }
                    if(isset($var['normal'])){
                        $param->normal = $var['normal'];
                    }
                    if(isset($var['xtablet'])){
                        $param->xtablet = $var['xtablet'];
                    }
                    if(isset($var['tablet'])){
                        $param->tablet = $var['tablet'];
                    }
                    if(isset($var['mobile'])){
                        $param->mobile = $var['mobile'];
                    }
                }

                $splparams[$i] = $param;
            }
        }

        //build data
        $datas = array();
        foreach ($splparams as $idx => $splparam){
            $param = (object)$splparam;

            $data = '';
            $data .= isset($param->default) ? ' data-default="' . $param->default . '"' : '';
            $data .= isset($param->wide) ? ' data-wide="' . $param->wide . '"' : '';
            $data .= isset($param->normal) ? ' data-normal="' . $param->normal . '"' : '';
            $data .= isset($param->xtablet) ? ' data-xtablet="' . $param->xtablet . '"' : '';
            $data .= isset($param->tablet) ? ' data-tablet="' . $param->tablet . '"' : '';
            $data .= isset($param->mobile) ? ' data-mobile="' . $param->mobile . '"' : '';

            $datas[] = $data;
        }

        //
        $vars['name'] = $name;
        $vars['splparams'] = $splparams;
        $vars['datas'] = $datas;
        $vars['cols'] = $cols;

        $this->loadBlock ('spotlight', $vars);
    }

    function megamenu($menutype){
        Plazart::import('menu/megamenu');

        //$file = PLAZART_TEMPLATE_PATH.'/etc/megamenu.ini';
        //$currentconfig = json_decode(@file_get_contents ($file), true);
        $currentconfig = json_decode($this->getParam('mm_config', ''), true);
        $mmconfig = ($currentconfig && isset($currentconfig[$menutype])) ? $currentconfig[$menutype] : array();
        $menu = new PlazartMenuMegamenu ($menutype, $mmconfig);
        $menu->render();

        // add core megamenu.css in plugin
        // deprecated - will extend the core style into template megamenu.less & megamenu-responsive.less
        // to use variable overridden in template
        $this->addStyleSheet(PLAZART_URL.'/css/megamenu.css');
        if ($this->getParam('responsive', 1)) $this->addStyleSheet(PLAZART_URL.'/css/megamenu-responsive.css');

        // megamenu.css override in template
        $this->addCss ('megamenu');
    }

    /**
     * Get data property for layout - responsive layout
     *
     * @param $layout object
     *     Layout configuration
     * @param $col int
     *     Column number, start from 0
     *
     * @return string Block content
     */
    function getData ($layout, $col) {
        $data = '';
        foreach ($layout as $device => $width) {
            if (!isset ($width[$col]) || !$width[$col]) continue;
            $data .= " data-$device=\"{$width[$col]}\"";
        }
        return $data;
    }

    /**
     * Get layout column class
     *
     * @param $layout object
     *     Layout configuration
     * @param $col int
     *     Column number, start from 0
     *
     * @return string Block content
     */
    function getClass ($layout, $col) {
        $width = $layout->default;
        if (!isset ($width[$col]) || !$width[$col]) return "";
        return $width[$col];
    }

    /**
     * Render page class
     */
    function bodyClass () {
        $input = JFactory::getApplication()->input;
        if($input->getCmd('option', '')){
            $classes[] = $input->getCmd('option', '');
        }
        if($input->getCmd('view', '')){
            $classes[] = 'view-' . $input->getCmd('view', '');
        }
        if($input->getCmd('layout', '')){
            $classes[] = 'layout-' . $input->getCmd('layout', '');
        }
        if($input->getCmd('task', '')){
            $classes[] = 'task-' . $input->getCmd('task', '');
        }
        if($input->getCmd('Itemid', '')){
            $classes[] = 'itemid-' . $input->getCmd('Itemid', '');
        }

        $menu = JFactory::getApplication()->getMenu();
        if($menu){
            $active = $menu->getActive();
            $default = $menu->getDefault();

            if ($active) {
                if($default && $active->id == $default->id){
                    $classes[] = 'home';
                }

                if ($active->params && $active->params->get('pageclass_sfx')) {
                    $classes[] = $active->params->get('pageclass_sfx');
                }
            }
        }

        echo implode(' ', $classes);
    }

    /**
     * Wrap of document countModules function, get position from configuration before calculate
     */
    function countModules($positions)
    {
        $pos = $this->getPosname ($positions);
        return $this->_tpl && method_exists($this->_tpl, 'countModules') ? $this->_tpl->countModules ($pos) : 0;
    }

    /**
     * Wrap of document countModules function, get position from configuration before calculate
     */
    function checkSpotlight($name, $positions)
    {
        $poss = array();

        for($i = 1; $i <= self::$maxcolumns; $i++){
            $param = $this->getLayoutSetting('block'.$i.'@'.$name);
            if(empty($param)){
                break;
            } else {
                $param = (object)$param;
                $poss[] = isset($param->position) ? $param->position : '';
            }
        }

        if(empty($poss)){
            $poss = preg_split('/\s*,\s*/', $positions);
        }

        return $this->_tpl && method_exists($this->_tpl, 'countModules') ? $this->_tpl->countModules (implode(' or ', $poss)) : 0;
    }

    /**
     * Check system messages
     */
    function hasMessage()
    {
        // Get the message queue
        $messages = JFactory::getApplication()->getMessageQueue();
        return !empty($messages);
    }

    /**
     * Get position name
     *
     * @param $poskey string
     *     the key used in block
     */
    function getPosname ($condition) {
        $operators = '(,|\+|\-|\*|\/|==|\!=|\<\>|\<|\>|\<=|\>=|and|or|xor)';
        $words = preg_split('# ' . $operators . ' #', $condition, null, PREG_SPLIT_DELIM_CAPTURE);
        for ($i = 0, $n = count($words); $i < $n; $i += 2) {
            // odd parts (modules)
            $name = strtolower($words[$i]);
            $words[$i] = $this->getLayoutSetting ($name, $name);
        }

        $poss = '';
        foreach ($words as $word) {
            if(is_string($word)){
                $poss .= ' ' . $word;
            } else {
                $poss .= ' ' . (is_array($word) ? $word['position'] : (isset($word->position) ? $word->position : $name));
            }
        }
        $poss = trim($poss);
        return $poss;
    }

    /**
     * echo position name
     *
     * @param $poskey string
     *     the key used in block
     */
    function posname ($condition) {
        echo $this->getPosname ($condition);
    }

    /**
     * Alias of posname
     *
     */
    function _p ($condition) {
        $this->posname ($condition);
    }

    /**
     * add position additinal class
     *
     * @param $poskey string
     *     the key used in block
     */

    function _c ($name, $cls = array()){
        $data = '';
        $param = $this->getLayoutSetting($name, '');

        if(empty($param) && is_string($cls)){
            $data = ' ' . $cls;
        } else if (is_array($cls)){
            if(empty($param)){
                $param = (object)$cls;
            }

            $data = '"';
            $data .= isset($param->default) ? ' data-default="' . $param->default . '"' : '';
            $data .= isset($param->normal) ? ' data-normal="' . $param->normal . '"' : '';
            $data .= isset($param->wide) ? ' data-wide="' . $param->wide . '"' : '';
            $data .= isset($param->xtablet) ? ' data-xtablet="' . $param->xtablet . '"' : '';
            $data .= isset($param->tablet) ? ' data-tablet="' . $param->tablet . '"' : '';
            $data .= isset($param->mobile) ? ' data-mobile="' . $param->mobile . '"' : '';

            if($data == '"'){
                $data = '';
            } else {
                $data = ' plazartrespon' . substr($data, 0, strrpos($data, '"'));
            }
        }

        echo $data;
    }

    /**
     * Add current template css base on template setting.
     *
     * @param $name String
     *     file name, without .css
     *
     * @return string Block content
     */
    function addCss ($name, $addresponsive = true, $addtheme = true) {
        $responsive = $addresponsive ? $this->getParam('responsive', 1) : false;
        $theme  =   $addtheme ? $this->getParam('theme', 'default') : false;
        $url = $theme ? PlazartPath::getUrl('css/themes/' .$theme. '/' . $name . '.css') : PlazartPath::getUrl('css/' . $name . '.css');
        // Add this css into template
        if ($url) {
            $this->addStyleSheet($url);
        }

        if ($responsive) {
            $this->addCss ($name.'-responsive', false);
        }
    }

    /**
     * Add Plazart basic head
     */
    function addHead () {
        // BOOTSTRAP CSS
        $this->addCss ('bootstrap', false);
        $this->addCss ('bootstrap-responsive');
        // TEMPLATE CSS
        $this->addCss ('template', false);

        // Add scripts
        if(version_compare(JVERSION, '3.0', 'ge')){
            JHtml::_('jquery.framework');
        } else {
            $scripts = @$this->_scripts;
            $jqueryIncluded = 0;
            if(is_array($scripts) && count($scripts)) {
                $pattern = '/jquery([-_]*\d+(\.\d+)+)?(\.min)?\.js/i';//is jquery core
                foreach ($scripts as $script => $opts) {
                    if(preg_match($pattern, $script)) {
                        $jqueryIncluded = 1;
                    }
                }
            }

            if(!$jqueryIncluded) {
                $this->addScript (PLAZART_URL.'/js/jquery-1.8.3' . ($this->getParam('devmode', 0) ? '' : '.min') . '.js');
                $this->addScript (PLAZART_URL.'/js/jquery.noconflict.js');
            }
        }
        define('JQUERY_INCLUED', 1);


        // As joomla 3.0 bootstrap is buggy, we will not use it
        $this->addScript (PLAZART_URL.'/bootstrap/js/bootstrap.js');

        // add css/js for off-canvas
        if ($this->getParam('navigation_collapse_offcanvas', 1)) {
            $this->addCss ('off-canvas', false, false);
            $this->addScript (PLAZART_URL.'/js/off-canvas.js', false);
        }

        $this->addScript (PLAZART_URL.'/js/script.js');

        //menu control script
        if ($this->getParam ('navigation_trigger', 'hover') == 'hover'){
            $this->addScript (PLAZART_URL.'/js/menu.js');
        }

        //check and add additional assets
        $this->addExtraAssets();
    }

    /**
     * Update head - detect if devmode or themermode is enabled and less file existed, use less file instead of css
     */
    function updateHead () {

        // As Joomla 3.0 bootstrap is buggy, we will not use it
        // We also prevent both Joomla bootstrap and Plazart bootsrap are loaded
        $plazartbootstrap = false;
        $jabootstrap = false;
        if(version_compare(JVERSION, '3.0', 'ge')){
            $doc = JFactory::getDocument();
            $scripts = array();
            foreach ($doc->_scripts as $url => $script) {
                if(strpos($url, PLAZART_URL.'/bootstrap/js/bootstrap.js') !== false){
                    $plazartbootstrap = true;
                    if($jabootstrap){ //we already have the Joomla bootstrap and we also replace to Plazart bootstrap
                        continue;
                    }
                }

                if(preg_match('@media/jui/js/bootstrap(.min)?.js@', $url)){
                    if($plazartbootstrap){ //we have Plazart bootstrap, no need to add Joomla bootstrap
                        continue;
                    } else {
                        $scripts[PLAZART_URL.'/bootstrap/js/bootstrap.js'] = $script;
                    }

                    $jabootstrap = true;
                } else {
                    $scripts[$url] = $script;
                }
            }

            $doc->_scripts = $scripts;
        }
        // end update javascript

        $minify = $this->getParam('minify', 0);
        //only check for minify if devmode is disabled

        if($minify){
            Plazart::import ('core/minify');
            PlazartMinify::optimizecss($this);
        }
    }

    /**
     * Add some other condition assets (css, javascript)
     */
    function addExtraAssets(){
        $base = JURI::base(true);
        $regurl = '#(http|https)://([a-zA-Z0-9.]|%[0-9A-Za-z]|/|:[0-9]?)*#iu';
        foreach(array(PLAZART_PATH, PLAZART_TEMPLATE_PATH) as $bpath){
            //full path
            $afile = $bpath . '/etc/assets.xml';
            if(is_file($afile)){

                //load xml
                $axml = JFactory::getXML($afile);
                //parse stylesheets first if exist
                if($axml){
                    foreach($axml as $node => $nodevalue){
                        //ignore others node
                        if($node == 'stylesheets' || $node == 'scripts'){
                            foreach ($nodevalue->file as $file) {
                                $compatible = $file['compatible'];
                                if($compatible) {
                                    $parts = explode(' ', $compatible);
                                    $operator = '='; //exact equal to
                                    $operand = $parts[1];
                                    if(count($parts) == 2){
                                        $operator = $parts[0];
                                        $operand = $parts[1];
                                    }

                                    //compare with Joomla version
                                    if(!version_compare(JVERSION, $operand, $operator)){
                                        continue;
                                    }
                                }

                                $url = (string)$file;
                                if(substr($url, 0, 2) == '//'){ //external link

                                } else if ($url[0] == '/'){ //absolute link from based folder
                                    $url = is_file(JPATH_ROOT . $url) ? $base . $url : false;
                                } else if (!preg_match($regurl, $url)) { //not match a full url -> sure internal link
                                    $url = PlazartPath::getUrl($url);		// so get it
                                }

                                if($url){
                                    if($node == 'stylesheets'){
                                        $this->addStylesheet($url);
                                    } else {
                                        $this->addScript($url);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }


    }

    function paramToStyle($style, $paramname = '', $isurl = false){
        if($paramname == ''){
            $paramname = $style;
        }
        $param = $this->getParam($paramname);

        if (!$param) return '';

        if ($isurl) {
            return "$style:url($param);";
        } else {
            return "$style:$param".(is_numeric($param) ? 'px;':';');
        }
    }

    /**
     * Auto generate optimize width in a row fit to 12 grid
     * @var (int) numpos: number columns in row
     */
    function fitWidth($numpos){
        $result = array();
        $avg = floor(self::$maxgrid / $numpos);
        $sum = 0;

        for($i = 0; $i < $numpos - 1; $i++){
            $result[] = $avg;
            $sum += $avg;
        }

        $result[] = self::$maxgrid - $sum;

        return $result;
    }

    /**
     * Generate auto calculate width
     */
    function genWidth($layout, $numpos){

        $cmaxcol = self::$maxcol[$layout];
        $cminspan = ($layout == 'mobile') ? self::$maxgrid : self::$minspan[$layout];
        $total = $cminspan * $numpos;
        $sum = 0;

        if($total < self::$maxgrid) {
            return $this->fitWidth($numpos);
        } else {
            $result = array();
            $rows = ceil($total / self::$maxgrid);
            $cols = ceil($numpos / $rows);

            for($i = 0; $i < $rows - 1; $i++){
                $result = array_merge($result, $this->fitWidth($cols));
                $numpos -= $cols;
            }

            $result = array_merge($result, $this->fitWidth($numpos));
        }

        return $result;
    }
}
?>